package net.rvb1.gwt.grad.ui.client.menu;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.MenuItemSeparator;
import com.google.gwt.user.client.ui.Widget;

public class ContextMenu extends DecoratedPopupPanel {
  private MenuBar menuBar;

  public ContextMenu() {
    this.menuBar = new MenuBar(true);
    super.setWidget(menuBar);

    menuBar.setStylePrimaryName("grad-ContextMenu");
    setStylePrimaryName("grad-ContextMenu-DecoratedPopupPanel");

    setAutoOpen(true);
    setAutoHideEnabled(true);
    setFocusOnHoverEnabled(false);
    setAutoHideOnHistoryEventsEnabled(true);
  }

  /**
   * Not supported in this panel. There is only one widget : the menu.
   */
  @Override
  public void add(Widget w) {
    throw new UnsupportedOperationException("Using setWidget(..) in ContextMenu is not supported.");
  }

  public MenuItem addItem(MenuItem item) {

    insertHideCommand(item);

    return menuBar.addItem(item);
  }

  public MenuItem addItem(SafeHtml html, MenuBar popup) {
    return addItem(new MenuItem(html, popup));
  }

  public MenuItem addItem(SafeHtml html, ScheduledCommand cmd) {
    return addItem(new MenuItem(html, cmd));
  }

  public MenuItem addItem(String text, boolean asHTML, MenuBar popup) {
    return addItem(new MenuItem(text, asHTML, popup));
  }

  public MenuItem addItem(String text, boolean asHTML, ScheduledCommand cmd) {
    return addItem(new MenuItem(text, asHTML, cmd));
  }

  public MenuItem addItem(String text, MenuBar popup) {
    return addItem(new MenuItem(text, popup));
  }

  public MenuItem addItem(String text, ScheduledCommand cmd) {
    return addItem(new MenuItem(text, cmd));
  }

  public MenuItemSeparator addSeparator() {
    return menuBar.addSeparator();
  }

  public MenuItemSeparator addSeparator(MenuItemSeparator separator) {
    return menuBar.addSeparator(separator);
  }

  public void clearItems() {
    menuBar.clearItems();
  }

  public void closeAllChildren(boolean focus) {
    menuBar.closeAllChildren(focus);
  }

  public boolean getAutoOpen() {
    return menuBar.getAutoOpen();
  }

  public int getItemIndex(MenuItem item) {
    return menuBar.getItemIndex(item);
  }

  public int getSeparatorIndex(MenuItemSeparator item) {
    return menuBar.getSeparatorIndex(item);
  }

  public MenuItem insertItem(MenuItem item, int beforeIndex) throws IndexOutOfBoundsException {

    insertHideCommand(item);

    return menuBar.insertItem(item, beforeIndex);
  }

  public MenuItemSeparator insertSeparator(int beforeIndex) {
    return menuBar.insertSeparator(beforeIndex);
  }

  public MenuItemSeparator insertSeparator(MenuItemSeparator separator, int beforeIndex)
      throws IndexOutOfBoundsException {
    return menuBar.insertSeparator(separator, beforeIndex);
  }

  public boolean isFocusOnHoverEnabled() {
    return menuBar.isFocusOnHoverEnabled();
  }

  public void moveSelectionDown() {
    menuBar.moveSelectionDown();
  }

  public void moveSelectionUp() {
    menuBar.moveSelectionUp();
  }

  public void removeItem(MenuItem item) {
    menuBar.removeItem(item);
  }

  public void removeSeparator(MenuItemSeparator separator) {
    menuBar.removeSeparator(separator);
  }

  public void selectItem(MenuItem item) {
    menuBar.selectItem(item);
  }

  public void setAutoOpen(boolean autoOpen) {
    menuBar.setAutoOpen(autoOpen);
  }

  public void setFocusOnHoverEnabled(boolean enabled) {
    menuBar.setFocusOnHoverEnabled(enabled);
  }

  /**
   * Not supported in this panel. There is only one widget : the menu.
   */
  @Override
  public final void setWidget(Widget w) {
    throw new UnsupportedOperationException("Using setWidget(..) in ContextMenu is not supported.");
  }

  /**
   * Sets a custom command which hides the popup before calling the user supplied command which is
   * in <code>item</code>.
   * 
   * @param item The {@link MenuItem} for whom we replace it's command.
   */
  private void insertHideCommand(MenuItem item) {
    final Scheduler.ScheduledCommand userSuppliedscheduledCommand = item.getScheduledCommand();
    item.setScheduledCommand(new Scheduler.ScheduledCommand() {
      public void execute() {
        hide();
        if (userSuppliedscheduledCommand != null) {
          userSuppliedscheduledCommand.execute();
        }
      }
    });
  }

}
